Osetreni DragDrop na formu

Otázka od: Ing. Igor Kapoun

25. 6. 2004 12:49

Potreboval bych osetrit udalost pretazeni ikony souboru napr. z pruzkumnika
nebo z WinCommanderu na formular me aplikace (ekvivalent pretazeni ikony
souboru za ucelem kopirovani nebo presunu souboru mezi dvema okny).
Potrebuji zjistit nazev souboru a cestu. Pomuze mi nekdo? Dekuji.
Igor


Odpovedá: Ing. Pavel Spisar

25. 6. 2004 13:27

podivej se po komponente FileDrop od Thomas Werner,
pripadne napis mimo konferenci (funguje v D3)
Ing. Igor Kapoun wrote:
> Potreboval bych osetrit udalost pretazeni ikony souboru napr. z
> pruzkumnika nebo z WinCommanderu na formular me aplikace (ekvivalent
> pretazeni ikony souboru za ucelem kopirovani nebo presunu souboru
> mezi dvema okny). Potrebuji zjistit nazev souboru a cestu. Pomuze mi
> nekdo? Dekuji.
> Igor


Odpovedá: Ondrej Kelle

25. 6. 2004 13:32

> Potreboval bych osetrit udalost pretazeni ikony souboru napr.
> z pruzkumnika nebo z WinCommanderu na formular me aplikace
> (ekvivalent pretazeni ikony souboru za ucelem kopirovani
> nebo presunu souboru mezi dvema okny).
> Potrebuji zjistit nazev souboru a cestu. Pomuze mi nekdo? Dekuji.

Da sa to aj cez OLE Drag & Drop, ale pre drag&drop suborov z explorera
(alebo inych aplikacii, ktore pouzivaju CF_HDROP format) mozes pouzit
jednoduchsi sposob cez DragAcceptFiles a spracovanie WM_DROPFILES.
Na to som si napisal jeden velmi jednoduchy komponent, snad Ti pomoze.
Staci mu nastavit vlastnost Control (napriklad listview alebo samotny
formular) a napisat si handler na udalost OnDropFiles.
Ak v tom najdes nejaky bug, daj mi prosim vediet, ja to pouzivam zatial bez
problemov.

unit DropFiles;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TDropFilesEvent = procedure (Sender: TObject; Files: TStrings; X, Y:
Integer) of object;

  TDropFiles = class(TComponent)
  private
    FControl: TWinControl;
    FFiles: TStrings;
    FOldWndProc: TWndMethod;
    FSorted: Boolean;

    FOnDropFiles: TDropFilesEvent;

    procedure SetControl(AControl: TWinControl);
    procedure WndProc(var Message: TMessage);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation);
override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Control: TWinControl read FControl write SetControl;
    property Sorted: Boolean read FSorted write FSorted default False;

    property OnDropFiles: TDropFilesEvent read FOnDropFiles write
FOnDropFiles;
  end;

procedure Register;

implementation

uses
  ShellApi;

procedure Register;
begin
  RegisterComponents('Additional', [TDropFiles]);
end;

{ TDropFiles private }

procedure TDropFiles.SetControl(AControl: TWinControl);
begin
  if AControl <> FControl then
  begin
    if (csDesigning in ComponentState) then
      FControl := AControl
    else
    begin
      if Assigned(FControl) then
      begin
        DragAcceptFiles(FControl.Handle, False);
        FControl.WindowProc := FOldWndProc;
        FOldWndProc := nil;
      end;
      FControl := AControl;
      if Assigned(FControl) then
      begin
        DragAcceptFiles(FControl.Handle, True);
        FOldWndProc := FControl.WindowProc;
        FControl.WindowProc := WndProc;
      end;
    end;
  end;
end;

procedure TDropFiles.WndProc(var Message: TMessage);
var
  P: TPoint;
  I, Count, SLen: Integer;
  S: string;
begin
  case Message.Msg of
    WM_DESTROY:
      begin
        DragAcceptFiles(FControl.Handle, False);
        FControl.WindowProc := FOldWndProc;
        FOldWndProc(Message);
        FOldWndProc := nil;
        FControl := nil;
      end;
    WM_DROPFILES:
      begin
        FFiles := TStringList.Create;
        try
          TStringList(FFiles).Sorted := FSorted;
          Message.Result := 0;
          if Assigned(FOnDropFiles) then
          begin
            if DragQueryPoint(Message.WParam, P) then
            begin
              Count := DragQueryFile(Message.WParam, UINT(-1), '', 0);
              for I := 0 to Count - 1 do
              begin
                SLen := DragQueryFile(Message.WParam, I, '', 0);
                SetLength(S, SLen + 1);
                DragQueryFile(Message.WParam, I, PChar(S), SLen + 1);
                FFiles.Add(S);
              end;
              DragFinish(Message.WParam);
              FOnDropFiles(Self, FFiles, P.x, P.y);
            end;
          end;
        finally
          FFiles.Free;
          FOldWndProc(Message);
        end;
      end;
    else
      FOldWndProc(Message);
  end;
end;

{ TDropFiles protected }

procedure TDropFiles.Notification(AComponent: TComponent; Operation:
TOperation);
begin
  if (AComponent = FControl) and (Operation = opRemove) then
    SetControl(nil);
  inherited Notification(AComponent, Operation);
end;

{ TDropFiles public }

constructor TDropFiles.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FControl := nil;
  FOldWndProc := nil;
  FSorted := False;
end;

destructor TDropFiles.Destroy;
begin
  SetControl(nil);
  inherited Destroy;
end;

end.

HTH
TOndrej